package com.woniuxy.portal.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniuxy.common.consts.RedisConst;
import com.woniuxy.portal.mapper.AddressMapper;
import com.woniuxy.portal.model.entity.Address;
import com.woniuxy.portal.model.entity.China;
import com.woniuxy.portal.model.vo.AddressRequest;
import com.woniuxy.portal.model.vo.AddressVo;
import com.woniuxy.portal.service.AddressService;
import com.woniuxy.portal.service.ChinaService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class AddressServiceImpl extends ServiceImpl<AddressMapper, Address> implements AddressService {

    // RedisTemplate<String, Object>适用于大多数场景，
    // 需要时手动强转或者配置专用的RedisTemplate<String, China>缓存转换器
    private final RedisTemplate<String, Object> redisTemplate;
    private final ChinaService chinaService;
    private final AddressMapper addressMapper;

    @Autowired
    public AddressServiceImpl(RedisTemplate<String, Object> redisTemplate,
                              ChinaService chinaService, AddressMapper addressMapper) {
        this.redisTemplate = redisTemplate;
        this.chinaService = chinaService;
        this.addressMapper = addressMapper;
    }

    /**
     * 根据用户ID查询地址列表
     *
     * @param userId 用户ID
     * @return List<AddressVo> 地址VO列表
     */
    @Override
    public List<AddressVo> findByUserId(Long userId) {
        // 查询用户的所有地址信息
        List<Address> addressList = this.list(new QueryWrapper<Address>().eq("user_id", userId));
        // 将地址实体转换为VO对象，拼接完整地址标签
//        List<AddressVo> voList = addressList.stream().map(address -> {
//            String label = address.getProvince() + address.getCity() + address.getArea() + address.getDetailAddress();
//            return new AddressVo(address.getId(), label, address.getIsDefault());
//        }).collect(Collectors.toList());
//        return voList;
        return addressList.stream().map(address -> {
            String label = address.getProvince() + address.getCity() + address.getArea() + address.getDetailAddress();
            return new AddressVo(address.getId(), label, address.getIsDefault());
        }).collect(Collectors.toList());
    }

    /**
     * 查询所有的省份
     *
     * @return List<China> 省份列表
     */
    @Override
    public List<China> getAllProvince() {
        List<China> list;
        // 判断缓存中是否有key
        if (!redisTemplate.hasKey(RedisConst.PROVINCES)) {
            // 查询数据库
            list = chinaService.list(
                    Wrappers.lambdaQuery(China.class)
                            .eq(China::getPid, 0)
                            .ne(China::getId, 0).orderByAsc(China::getId)
            );
            // 查询结果放入Redis缓存，通过ZSet集合存储，id是分数
            list.forEach(china -> redisTemplate.opsForZSet().add(RedisConst.PROVINCES, china, china.getId()));
        } else {

            // 从Redis中获取所有元素（原版）
//            Set<China> members = redisTemplate.opsForZSet().range(RedisConst.PROVINCES, 0, -1);
//            list = new ArrayList<>(members);

            // 直接手动强转，就不配置专用的RedisTemplate缓存转换器了
            // 一步到位生成 List<China>，避免中间 Set -> List 的转换
            Set<Object> rawSet = redisTemplate.opsForZSet().range(RedisConst.PROVINCES, 0, -1);
            list = (rawSet == null ? Stream.empty() : rawSet.stream())
                    .filter(Objects::nonNull)
                    .map(obj -> (China) obj)
                    .collect(Collectors.collectingAndThen(
                            Collectors.toCollection(LinkedHashSet::new), // 去重 & 保持顺序
                            ArrayList::new)); // 最终转为 List
        }
        return list;
    }

    /**
     * 通过省的id查询省下所有的城市
     * #root.methodName 动态获取方法名称
     * #provinceId 动态获取方法参数
     *
     * @param provinceId 省份ID，用于查询该省下的所有城市
     * @return List<China> 返回指定省份下的所有城市列表
     */
    @Cacheable(cacheNames = RedisConst.CITIES, key = "#root.methodName + #provinceId")
    @Override
    public List<China> getAllCities(Integer provinceId) {
        // 根据省份ID查询所有城市信息
//        List<China> list = chinaService.list(Wrappers.lambdaQuery(China.class)
//                .eq(Objects.nonNull(provinceId), China::getPid, provinceId));
//        return list;
        return chinaService.list(Wrappers.lambdaQuery(China.class)
                .eq(Objects.nonNull(provinceId), China::getPid, provinceId));
    }

    /**
     * 通过城市的id查询城市下所有的地区
     *
     * @param cityId 城市ID，用于查询该城市下的所有地区
     * @return List<China> 返回指定城市下的所有地区列表
     */
    @Override
    @Cacheable(cacheNames = RedisConst.DISTRICTS, key = "#root.methodName + #cityId")
    public List<China> getAllDistricts(Integer cityId) {
        // 根据城市ID查询所有下属地区
//        List<China> list = chinaService.list(Wrappers.lambdaQuery(China.class)
//                .eq(Objects.nonNull(cityId), China::getPid, cityId));
//        return list;
        return chinaService.list(Wrappers.lambdaQuery(China.class)
                .eq(Objects.nonNull(cityId), China::getPid, cityId));
    }

    /**
     * 添加用户地址信息
     *
     * @param addressRequest 地址请求参数对象，包含省份、城市、区域等地址信息
     * @param userId         用户ID，用于关联地址信息到具体用户
     */
    @Override
    @Transactional  //开启事务
    public void addAddress(AddressRequest addressRequest, Long userId) {
        // 根据省份id，获取省份名称
        China province = chinaService.findById(addressRequest.getProvince());
        // 获取城市id，获取城市名称
        China city = chinaService.findById(addressRequest.getCity());
        // 获取区/县id，获取区/县名称
        Integer district = addressRequest.getDistrict();
        // Optional.ofNullable(district) 创建一个 Optional 对象，然后调用 map(chinaService::findById) 方法来处理 district 不为空的情况，最后使用 orElse(null) 来处理 district 为空的情况，避免了显式的 if 判断语句，使代码更加简洁和优雅。
        China area = Optional.ofNullable(district)
                .map(chinaService::findById)
                .orElse(null);
        // 封装地址信息
        Address address = new Address();
        // 属性拷贝
        BeanUtils.copyProperties(addressRequest, address);
        // 属性不同的则单独设置
        address.setProvince(province.getName());
        address.setCity(city.getName());
        //如果为空，则赋值空字符串
        address.setArea(area == null ? "" : area.getName());
        address.setStatus("1");
        address.setTelephone(addressRequest.getTel());
        address.setUserId(userId);
        // 判断是否为默认地址
        if (address.getIsDefault() == 1) {
            // 修改其他地址为不是默认地址，将isDefault = 0
            this.update(Wrappers.lambdaUpdate(Address.class)
                    .set(Address::getIsDefault, "0").eq(Address::getUserId, userId));
        }
        // 添加地址
        addressMapper.insert(address);
    }

}
